home *** CD-ROM | disk | FTP | other *** search
/ Adobe Graphics & Publishing SDK 1996 December / Adobe Graphics & Publishing SDK 1996 December.iso / mac / After Effects 3.1 SDK Mac / Examples / Effects Samples / Shifter / Shifter.c < prev   
Text File  |  1996-11-06  |  10KB  |  358 lines

  1. /**
  2.     Shifter.c
  3.     
  4.     Part of the Adobe After Effects 3.1 SDK.
  5.     Copyright (c)1993-96, Adobe Systems Inc, All Rights Reserved.
  6.  
  7.     This effect shifts the whole image to a new position with
  8.     sub-pixel accuracy.  The user specifies a point, and the
  9.     center of the layer is shifted to that point.  The user
  10.     also specifies a "Blend With Original" so the shifted image
  11.     can appear as a faded echo of the original.
  12.  
  13.     This demonstrates the use of:
  14.         the Iterate callback
  15.         the Subpixel Sample callback
  16.         a Point control
  17.         a Fixed Slider control
  18.         the Extent Hint rectangle (from the output image)
  19.  
  20.     Revision History
  21.         1.0, created by rb, 12 March 93
  22.         1.1, updated for AE 2.0, dmw, 11 Jan 94
  23.         1.2, updated for AE 2.0 PowerMac/Mac, dmw        
  24.         2.0, updated for AE 3.0, CW7, dmw
  25.         2.1, Added call to AEFX_CLR_STRUCT macro to clear out PF_ParamDef, ba, 6 Nov 96
  26. **/
  27.  
  28. #include "AE_EffectCB.h"
  29. #include "AE_Macros.h"
  30. #include <A4Stuff.h>
  31.  
  32. #define    MAJOR_VERSION        2
  33. #define    MINOR_VERSION        0
  34. #define    BUG_VERSION            0
  35. #define    STAGE_VERSION        PF_Stage_RELEASE
  36. #define    BUILD_VERSION        0
  37.  
  38. #define    NAME    "Shifter"
  39.  
  40.  
  41. /** Parameter Definition Constants
  42.  
  43.     Here we define the parameters, their default
  44.     settings, and minimum and maximum values.
  45.  
  46. **/
  47.  
  48. enum {
  49.     SHIFT_INPUT = 0,    /* params index of default input layer */
  50.     SHIFT_DISPLACE,        /* params index of offset point control */
  51.     SHIFT_BLEND,        /*   "      "   of blend with original slider */
  52.  
  53.     SHIFT_NUM_PARAMS
  54. };
  55.  
  56.  
  57. /* set default (x,y) of new center to the
  58.  * original center of the image (50%, 50%).
  59.  */
  60. #define SHIFT_DISPLACE_X_DFLT    (50L << 16)
  61. #define    SHIFT_DISPLACE_Y_DFLT    (50L << 16)
  62.  
  63. /* set blend to default to showing just the shifted version
  64.  * of the image.  Zero will represented full shifted, one will
  65.  * be full original, and in-between values will be blended.
  66.  * All of these numbers are in Fixed point.
  67.  */
  68.  
  69. #define    SHIFT_BLEND_MIN        (0L << 16)
  70. #define    SHIFT_BLEND_MAX        (1L << 16)
  71. #define    SHIFT_BLEND_DFLT    (0L << 16)
  72.  
  73.  
  74. /** Command Specific Subroutines
  75.  
  76.     This plug-in only deals with the commands:
  77.         PF_Cmd_ABOUT
  78.         PF_Cmd_GLOBAL_SETUP
  79.         PF_Cmd_GLOBAL_SETDOWN
  80.         PF_Cmd_PARAMS_SETUP
  81.         PF_Cmd_RENDER
  82.     All other commands are ignored.  There is a routine for
  83.     each command, and a main routine to dispatch at the bottom.
  84.  
  85. **/
  86.  
  87. static PF_Err About (
  88.     PF_InData        *in_data,
  89.     PF_OutData        *out_data,
  90.     PF_ParamDef        *params[],
  91.     PF_LayerDef        *output )
  92. {
  93. #define DESCRIPTION    "Blend in a shifted copy of the image."
  94.  
  95.     PF_SPRINTF(out_data->return_msg, "%s, v%d.%d\r%s",
  96.         NAME, MAJOR_VERSION, MINOR_VERSION, DESCRIPTION);
  97.  
  98.     return PF_Err_NONE;
  99. }
  100.  
  101.  
  102. static PF_Err GlobalSetup (
  103.     PF_InData        *in_data,
  104.     PF_OutData        *out_data,
  105.     PF_ParamDef        *params[],
  106.     PF_LayerDef        *output )
  107. {
  108.     PF_Err    err = PF_Err_NONE;
  109.  
  110.     /* Need to let AE know what version of the "Shifter" plug-in
  111.      * we are......
  112.      */
  113.      
  114.     out_data->my_version = PF_VERSION(MAJOR_VERSION, MINOR_VERSION,
  115.                                     BUG_VERSION, STAGE_VERSION, BUILD_VERSION);
  116.  
  117.     /* We are only going to iterate over the output extent
  118.      * Rectange, so we need to specify that flag...
  119.      */
  120.     out_data->out_flags |= PF_OutFlag_USE_OUTPUT_EXTENT;
  121.  
  122.     return err;
  123. }
  124.  
  125.  
  126. static PF_Err GlobalSetdown (
  127.     PF_InData        *in_data,
  128.     PF_OutData        *out_data,
  129.     PF_ParamDef        *params[],
  130.     PF_LayerDef        *output )
  131. {
  132.     /* We haven't actually allocated any global data,
  133.      * so we don't need to do anything here... */
  134.      
  135.     return PF_Err_NONE;
  136. }
  137.  
  138.  
  139. static PF_Err ParamsSetup (
  140.     PF_InData        *in_data,
  141.     PF_OutData        *out_data,
  142.     PF_ParamDef        *params[],
  143.     PF_LayerDef        *output)
  144. {
  145.     PF_Err            err = PF_Err_NONE;
  146.     PF_ParamDef        def;    /* scratch space for a parameter definition */
  147.  
  148.     /* Always clear out the PF_ParamDef structure before adding your parameters,
  149.      * this macro will do that. */
  150.     
  151.     AEFX_CLR_STRUCT(def);
  152.  
  153.     /* Create the POINT parameter... */
  154.  
  155.     def.param_type = PF_Param_POINT;
  156.     PF_STRCPY(def.name, "Shift Center To");
  157.     def.flags = 0;
  158.     def.u.td.x_value = def.u.td.x_dephault = SHIFT_DISPLACE_X_DFLT;
  159.     def.u.td.y_value = def.u.td.y_dephault = SHIFT_DISPLACE_Y_DFLT;
  160.     def.u.td.restrict_bounds = FALSE;    /* point can be anywhere */
  161.  
  162.     if (err = PF_ADD_PARAM(in_data, -1, &def)) return err;
  163.  
  164.     /* Create the FIXED SLIDER parameter...
  165.      * Note: now that we have called ADD_PARAM, we can re-use
  166.      * the same PF_ParamDef for the slider definition. */
  167.  
  168.     def.param_type = PF_Param_FIX_SLIDER;
  169.     PF_STRCPY(def.name, "Blend With Original");
  170.     def.flags = 0;
  171.     
  172.     /* NOTE: we must set these strings to empty strings to prevent
  173.      * garbage text from being displayed above our sliders... */
  174.      
  175.     def.u.fd.value_str[0] = def.u.fd.value_desc[0] = '\0';
  176.     def.u.fd.value = def.u.fd.dephault = SHIFT_BLEND_DFLT;
  177.     
  178.     /* NOTE: for this Blend slider, the valid min and max are
  179.      * the same as the min and max accessible by the slider. */
  180.      
  181.     def.u.fd.valid_min = def.u.fd.slider_min = SHIFT_BLEND_MIN;
  182.     def.u.fd.valid_max = def.u.fd.slider_max = SHIFT_BLEND_MAX;
  183.     
  184.     /* Let's let the user see 1 decimal place of precision,
  185.      * and have the value appear to go from 0 to 100 percent,
  186.      * rather than from 0 to 1 as it's stored internally... */
  187.      
  188.     def.u.fd.precision = 1;
  189.     def.u.fd.display_flags = 1;    /* display as percent flag */
  190.  
  191.     if (err = PF_ADD_PARAM(in_data, -1, &def)) return err;
  192.  
  193.     /* Set number of parameters before leaving */
  194.  
  195.     out_data->num_params = SHIFT_NUM_PARAMS;
  196.  
  197.     return err;
  198. }
  199.  
  200.  
  201. /* Iteration Function
  202.  *        The render routine uses PF_ITERATE to loop over all the pixels.
  203.  *        This function adds an offset to the given pixel and resamples
  204.  *        the original image at that offset point.  We will blend this
  205.  *        shifted image back with the original in the Render routine.
  206.  *
  207.  *        We will define a type called a ShiftInfo that contains all of
  208.  *        the information our ShiftImage function needs to know about
  209.  *        the effect parameters, and the stuff to do image resampling.
  210.  */
  211.  
  212. typedef struct {
  213.     Fixed    x_off;        /* x_offset for shifted image */
  214.     Fixed    y_off;        /* y_offset for shifted image */
  215.  
  216.     /* structures and function pointer for image resampling */
  217.     PF_ProgPtr    ref;
  218.     PF_SampPB    samp_pb;
  219.     PF_InData    *in_data;
  220. } ShiftInfo;
  221.  
  222.  
  223. static PF_Err ShiftImage (long refcon, long x, long y, PF_Pixel *in, PF_Pixel *out)
  224. {
  225.     register ShiftInfo    *si = (ShiftInfo *)refcon;
  226.     PF_InData            *in_data = si->in_data;
  227.     PF_Err                err;
  228.     Fixed                new_x, new_y;
  229.  
  230.     /* Resample original image at the offset point */
  231.  
  232.     new_x = ((long)x << 16) + si->x_off;    /* convert value to Fixed */
  233.     new_y = ((long)y << 16) + si->y_off;
  234.  
  235.     err = PF_SUBPIXEL_SAMPLE(new_x, new_y, &si->samp_pb, out);
  236.  
  237.     return err;
  238. }
  239.  
  240.  
  241. /* Render
  242.  *        To render our image, we need to set up a ShiftInfo structure
  243.  *        with the right information, then invoke the Iterate callback.
  244.  *        We will iterate only over the visible range of the output
  245.  *        image (that is, its extent hint), to save time.  Once we have
  246.  *        created the shifted image in the output buffer, we will blend
  247.  *        the input image into the output image.
  248.  *
  249.  *        NOTE: Using the Blend callback gives us an alpha-weighted
  250.  *        blend of the two images, so we will not get inappropriate
  251.  *        color distortions where the images do not overlap, or where
  252.  *        there is partial alpha.  Alpha weighting the color mixture
  253.  *        is a subtle thing that users may not consciously notice,
  254.  *        but gives better looking results, which they will.
  255.  *
  256.  *        NOTE: You will find that blending looks distinctly different
  257.  *        from compositing the shifted image onto the original -- where
  258.  *        the shifted copy does not overlap the original, it becomes
  259.  *        partially (or totally) transparent.  Compositing would not
  260.  *        do that.  Compositing could make an interesting effect, too,
  261.  *        but there is no need for it.  It can be easily achieved by
  262.  *        duplicating the layer, shifting the duplicate, and setting
  263.  *        the transparency slider.
  264.  */
  265.  
  266. static PF_Err Render ( 
  267.     PF_InData        *in_data,
  268.     PF_OutData        *out_data,
  269.     PF_ParamDef        *params[],
  270.     PF_LayerDef        *output )
  271. {
  272.     PF_Err            err = PF_Err_NONE;
  273.     ShiftInfo        si;
  274.     Fixed            blend;
  275.     short            lines;
  276.     PF_World        *input;
  277.  
  278.     input = ¶ms[SHIFT_INPUT]->u.ld;
  279.  
  280.     blend = params[SHIFT_BLEND]->u.fd.value;
  281.  
  282.     /* We convert the image width and height to Fixed values
  283.      * then divide by two, to calculate the Fixed point offset.
  284.      * Shifting left 15 bits effectively does this conversion.
  285.      */
  286.     si.x_off = ((long)input->width << 15) -        /* 1/2 width as Fixed */
  287.         params[SHIFT_DISPLACE]->u.td.x_value;
  288.  
  289.     si.y_off = ((long)input->height << 15) -    /* 1/2 height as Fixed */
  290.         params[SHIFT_DISPLACE]->u.td.y_value;
  291.  
  292.     si.ref = in_data->effect_ref;
  293.     si.samp_pb.src = input;
  294.     si.in_data = in_data;
  295.  
  296.     if (blend == (1L << 16)) {
  297.         /* if blend is set to 100%, we don't have any work to do */
  298.  
  299.         err = PF_COPY(input, output, NULL, NULL);
  300.  
  301.     } else {
  302.         /* otherwise, iterate and blend */
  303.  
  304.         /* calculate how many lines we'll iterate over, for progress bar */
  305.         lines = output->extent_hint.bottom - output->extent_hint.top;
  306.  
  307.         err = PF_ITERATE(0, lines, input, &output->extent_hint,
  308.             (long)&si, ShiftImage, output);
  309.  
  310.         /* one of the advantages of using ITERATE, is that it
  311.          * automatically checks for user interruptions for us.
  312.          * It will return an error if the user interrupted, which
  313.          * we should dutifully pass back to the application.
  314.          */
  315.  
  316.         if (!err) {
  317.             err = PF_BLEND(output, input, blend, output);
  318.         }
  319.     }
  320.  
  321.     return err;
  322. }
  323.  
  324.  
  325. PF_Err main (
  326.     PF_Cmd            cmd,
  327.     PF_InData        *in_data,
  328.     PF_OutData        *out_data,
  329.     PF_ParamDef        *params[],
  330.     PF_LayerDef        *output )
  331. {
  332.     PF_Err        err = PF_Err_NONE;
  333.     
  334.     EnterCodeResource();        /* $$$ this assumes you're using Metrowerks */
  335.     
  336.     switch (cmd) {
  337.     case PF_Cmd_ABOUT:
  338.         err = About(in_data,out_data,params,output);
  339.         break;
  340.     case PF_Cmd_GLOBAL_SETUP:
  341.         err = GlobalSetup(in_data,out_data,params,output);
  342.         break;
  343.     case PF_Cmd_PARAMS_SETUP:
  344.         err = ParamsSetup(in_data,out_data,params,output);
  345.         break;
  346.     case PF_Cmd_GLOBAL_SETDOWN:
  347.         err = GlobalSetdown(in_data,out_data,params,output);
  348.         break;
  349.     case PF_Cmd_RENDER:
  350.         err = Render(in_data,out_data,params,output);
  351.         break;
  352.     }
  353.  
  354.     ExitCodeResource();
  355.  
  356.     return err;
  357. }
  358.